#include "wifi_board.h"

#include "system_info.h"
#include "settings.h"

#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_http.h>
#include <esp_mqtt.h>
#include <esp_udp.h>
#include <tcp_transport.h>
#include <tls_transport.h>
#include <web_socket.h>
#include <esp_log.h>

#include <wifi_station.h>
#include <wifi_configuration_ap.h>
#include <ssid_manager.h>
#include "boards/audio_codecs/audio_codec.h"
#include "boards/audio_codecs/no_audio_codec.h"
#include "config.h"

static const char *TAG = "WifiBoard";

static std::string rssi_to_string(int rssi) {
    if (rssi >= -55) {
        return "Very good";
    } else if (rssi >= -65) {
        return "Good";
    } else if (rssi >= -75) {
        return "Fair";
    } else if (rssi >= -85) {
        return "Poor";
    } else {
        return "No network";
    }
}

WifiBoard::WifiBoard() {
    Settings settings("wifi", true);
    wifi_config_mode_ = settings.GetInt("force_ap") == 1;
    if (wifi_config_mode_) {
        ESP_LOGI(TAG, "force_ap is set to 1, reset to 0");
        settings.SetInt("force_ap", 0);
    }
}

void WifiBoard::EnterWifiConfigMode() {
    printf("进入配网\n");
    auto& wifi_ap = WifiConfigurationAp::GetInstance();
    wifi_ap.SetSsidPrefix(CONFIG_WIFI_CONF_NAME);
    wifi_ap.Start();

    // 显示 WiFi 配置 AP 的 SSID 和 Web 服务器 URL
    std::string hint = "请在手机上连接热点 ";
    hint += wifi_ap.GetSsid();
    hint += "，然后打开浏览器访问 ";
    hint += wifi_ap.GetWebServerUrl();
    // display->SetStatus(hint);
    ESP_LOGI(TAG,"%s",hint.c_str());

    // Wait forever until reset after configuration
    while (true) {
        int free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
        int min_free_sram = heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL);
        ESP_LOGI(TAG, "Free internal: %u minimal internal: %u", free_sram, min_free_sram);
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

void WifiBoard::StartNetwork() {
    // ESP_ERROR_CHECK(esp_event_loop_create_default());
    // User can press BOOT button while starting to enter WiFi configuration mode
    // wifi连接标志false，进入配网模式
    if (wifi_config_mode_) {
        EnterWifiConfigMode();
        return;
    }

    // WIFI名和密码不存在，进入配网模式
    auto& ssid_manager = SsidManager::GetInstance();
    auto ssid_list = ssid_manager.GetSsidList();
    if (ssid_list.empty()) {
        wifi_config_mode_ = true;
        EnterWifiConfigMode();
        return;
    }

    // 连接WIFI
    auto& wifi_station = WifiStation::GetInstance();
    wifi_station.OnScanBegin([this]() {
        ESP_LOGI(TAG,"正在扫描 WiFi 网络");
    });
    wifi_station.OnConnect([this](const std::string& ssid) {
        ESP_LOGI(TAG,"正在连接 WiFi：%s",ssid.c_str());
    });
    wifi_station.OnConnected([this](const std::string& ssid) {
        ESP_LOGI(TAG,"已连接 WiFi：%s",ssid.c_str());
    });
    wifi_station.Start();

    // Try to connect to WiFi, if failed, launch the WiFi configuration AP
    if (!wifi_station.WaitForConnected(10 * 1000)) {
        wifi_station.Stop();
        wifi_config_mode_ = true;
        EnterWifiConfigMode();
        return;
    }
}


WebSocket* WifiBoard::CreateWebSocket(std::string url) {
    if (url.find("wss://") == 0) {
        return new WebSocket(new TlsTransport());
    } else {
        return new WebSocket(new TcpTransport());
    }
    return nullptr;
}


bool WifiBoard::GetNetworkState(std::string& network_name, int& signal_quality, std::string& signal_quality_text) {
    if (wifi_config_mode_) {
        auto& wifi_ap = WifiConfigurationAp::GetInstance();
        network_name = wifi_ap.GetSsid();
        signal_quality = -99;
        signal_quality_text = wifi_ap.GetWebServerUrl();
        return true;
    }
    auto& wifi_station = WifiStation::GetInstance();
    if (!wifi_station.IsConnected()) {
        return false;
    }
    network_name = wifi_station.GetSsid();
    signal_quality = wifi_station.GetRssi();
    signal_quality_text = rssi_to_string(signal_quality);
    return signal_quality != -1;
}

AudioCodec* WifiBoard::GetAudioCodec() {
    static NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,
        AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN);
    return &audio_codec;
}

DECLARE_BOARD(WifiBoard)